package objects;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Iterator;

import common.Constants;
import common.PacketFormatter;
import common.RealmConf;
import common.RealmServer;

public class InterServerThread implements Runnable
{
	private Socket _s;
	private Thread _t;
	private GameServer _gS;
	private BufferedReader _in;
	private PrintWriter _out;
	private boolean _running = false, _auth = false;
	
	public InterServerThread(Socket s)
	{
		_s = s;
		try
		{
			_in = new BufferedReader(new InputStreamReader(_s.getInputStream()));
			_out = new PrintWriter(_s.getOutputStream());
		}catch(Exception e){return;};
		
		_t = new Thread(this);
		_t.setDaemon(true);
		_t.start();
	}
	
    @Override
	public void run()
	{
		_running = true;
		try
    	{
			String packet = "";
			char charCur[] = new char[1];
	    	while(_in.read(charCur, 0, 1)!=-1 && RealmServer.isRunning() && _running)
	    	{
	    		if (charCur[0] != '\u0000' && charCur[0] != '\n' && charCur[0] != '\r')
		    	{
	    			packet += charCur[0];
		    	}else if(packet != "")
		    	{
		    		if(RealmConf._debug)RealmServer.writeLine("IS: Recv << "+packet);
		    		parsePacket(packet);
		    		packet = "";
		    	}
	    	}
    	}catch(IOException e)
    	{
    		//todo
    	}
    	finally
    	{
    		if(_gS != null)
    		{
    			_gS.setState(Constants.SERVER_STATE_OFFLINE);
    			RealmServer.writeLine("ISConnection from GameServer "+_gS.getId()+"("+_s.getInetAddress().getHostAddress()+") closed");
                updateGSState();
         }
    		_out.close();
    		try
    		{
    			_in.close();
    		}catch(Exception e){}
			try
    		{
    			_s.close();
    		}catch(Exception e){}

			
    	}
	}
    
    private void parsePacket(String packet)
    {
    	byte opcode = Byte.parseByte(packet.substring(0,2));
    	packet = packet.substring(2);

    	//Refuse connection if not valid
    	if(opcode != 0x00 && _auth == false)
    	{
    		RealmServer.writeLine("Receive packet from non valid gameserver: "+_s.getInetAddress().getHostAddress());
    		_running = false;
    		return;
    	}
    	
    	switch(opcode)
    	{
    		//Recv Password
    		case 0x00:
    	    	//if bad inter server password
    	    	if(!RealmConf._interPass.equals(packet))
    	    	{
    	    		RealmServer.writeLine("Receive wrong password from "+_s.getInetAddress().getHostAddress());
    	    		_running = false;
    	    		break;
    	    	}
    	    	_auth = true;
    	    	RealmServer.writeLine("Receive new connexion from "+_s.getInetAddress().getHostAddress()+", waiting server informations ...");
    			sendPacket(PacketFormatter.getISAcceptedPasswordPacket());
    	    	break;
    			
    		//Recv ID,State population & port : id;state;pop;port
    		case 0x01:
    			String[] splitted = packet.split(";");
    			byte id = Byte.parseByte(splitted[0]);
    			byte state = Byte.parseByte(splitted[1]);
    			byte pop = Byte.parseByte(splitted[2]);
    			String address = splitted[3];
    			short port = Short.parseShort(splitted[4]);
    			boolean useIP = Byte.parseByte(splitted[5]) == 1;
    			_gS = new GameServer(id,state,pop,address,port,useIP,this);
    			//If already registered & online; stop listening (kick)
    			if(!RealmServer.addGameServer(id,_gS))
    			{
    				RealmServer.writeLine("ISError: Receive Server information from existing and online server (id="+id+")");
    				_running = false;
    				break;
    			}
    			sendPacket(PacketFormatter.getISAcceptedInformationsPacket());
    			RealmServer.writeLine("New GameServer Registred: id="+id+" state="+state+" Adress: "+address+":"+port);
                        break;
    		//Other opcode are for information's transmitting 
    		
    		//Update State
    		case 0x0A:
    			if(_gS == null)break;//ignore
    			
    			try
    			{
    				_gS.setState(Byte.parseByte(packet));
    			}catch(Exception e){break;};
    			
    			RealmServer.writeLine("GameServer "+_gS.getId()+" had updated his state to "+packet);
    			sendPacket(PacketFormatter.getISUpdateStateOkPacket());
                updateGSState();
                
                break;
    	}
    }
    
    public void sendPacket(String packet)
    {
    	if(!_s.isConnected() || _s.isClosed())return;
    	
    	try
    	{
    		_out.write(packet + (char)0x00);
    		_out.flush();
    		if(RealmConf._debug)RealmServer.writeLine("IS: Send >> "+packet);
    	}catch(Exception e)
    	{
    		_out.close();
    		_running = false;
    		try {
				_s.close();
			} catch (IOException e1) {}
    	};
    }

	public void registerNewWaitingAccount(Account acc)
	{       
        common.SQLMgr.getCharNumbByAccount(RealmThread.gsIDSelect, acc.getSubscribeTimeEnd());
		sendPacket(PacketFormatter.getISRegisterAccountInWQPacket(acc.getGuid(),acc.getGmLevel(), acc.getAnswer(), acc.getPseudo(),acc.getSubscribeTimeEnd(), common.SQLMgr.CharacterNumb));
	}
	
	public void updateGSState()
	{
		Iterator<RealmThread> iter = RealmServerThread.get_clients().iterator();
		while(iter.hasNext())
		{
			RealmThread realmThread = iter.next();
			if(realmThread.getAccount() != null && realmThread.getAccount().getConnected())
			{
				RealmServer.writeLine("Connecte : " + realmThread.getAccount().getConnected());
				realmThread.sendPacket(PacketFormatter.getAccountHostListPacket(realmThread.getAccount().isSubscriber()));
     		}
		}
	}

}
